package com.itfreer.data.sqlite;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import com.itfreer.data.general.ConnectionInfo;

import java.util.HashMap;
import java.util.Set;

/**
 * 定义事务处理程序块
 */
public class TransactionsBlock {

    /**
     * 多线程锁
     */
    private static final Object lockObj = new Object();

    /**
     * 事务缓存
     */
    private static final HashMap<String, HashMap<String, SQLiteDatabase>> transactionCache = new HashMap<String, HashMap<String, SQLiteDatabase>>();

    /**
     * 事务层数
     */
    private static final HashMap<String, Integer> transactionRegs = new HashMap<String, Integer>();

    /**
     * 在事务块中是否调用过Rollback
     */
    private static final HashMap<String, Boolean> hasInvokeRollback = new HashMap<String, Boolean>();

    /**
     * 释放数据库对象
     * @param context
     * @param cInfo
     */
    public static void RefreshDatabase(Context context, ConnectionInfo cInfo, SQLiteDatabase database){
        if(HasNextTransactions()){
            return;
        }
        SQLiteDatabasePool pool = SQLiteDatabasePool.getInstance(context, cInfo, true);
        pool.releaseSQLiteDatabase(database);
    }

    /**
     * 获取事务处理信息下的数据库处理器
     * @param context
     * @param cInfo
     * @return
     */
    public static SQLiteDatabase GetDatabase(Context context, ConnectionInfo cInfo){
        synchronized (lockObj){
            String key = GetGlobeKey();
            // 是否注册
            if (transactionCache.containsKey(key)) {
                synchronized (lockObj){
                    HashMap<String, SQLiteDatabase> dbInfoList = transactionCache.get(key);
                    if(dbInfoList==null){
                        dbInfoList = new HashMap<String, SQLiteDatabase>();
                        transactionCache.put(key, dbInfoList);
                    }
                    if (dbInfoList.containsKey(cInfo.getConnectionStr())){
                        return dbInfoList.get(cInfo.getConnectionStr());
                    } else {
                        SQLiteDatabase dbInfo = AddTransctions(context, cInfo);
                        dbInfo.beginTransaction();
                        dbInfoList.put(cInfo.getConnectionStr(), dbInfo);
                        return dbInfo;
                    }
                }
            } else {
                try {
                    // 没注册，不需要事务处理
                    SQLiteDatabase dbInfo = AddTransctions(context, cInfo);
                    return dbInfo;
                } catch (Exception ex) {
                    throw ex;
                }
            }
        }
    }

    /**
     * 添加数据信息
     * @param cInfo
     * @return
     */
    private static SQLiteDatabase AddTransctions(Context context, ConnectionInfo cInfo) {
        try {
            SQLiteDatabasePool pool = SQLiteDatabasePool.getInstance(context, cInfo, true);
            SQLiteDatabase sqlLiteDatabase = pool.getSQLiteDatabase();
            return sqlLiteDatabase;
        } catch (Exception ex) {
            throw ex;
        }
    }

    /**
     * 获取全局的一个key
     * @return
     */
    private static String GetGlobeKey() {
        synchronized (lockObj){
            String key = "_" + Thread.currentThread().getId();
            return key;
        }
    }

    /**
     * 开始一个事务
     */
    public static void StartTransactions() {
        synchronized (lockObj){
            String key = GetGlobeKey();
            // 开始一个事务
            if (!transactionCache.containsKey(key)) {
                transactionCache.put(key, null);
                transactionRegs.put(key, 1);
                hasInvokeRollback.put(key, false);
            } else {
                // 说明上级存在注册的事务块，当前块不启做用
                int num = transactionRegs.get(key);
                num++;
                transactionRegs.put(key, num);
            }
        }
    }

    /**
     * 停止一个事务
     * @param saveEdits
     */
    public static void StopTransactions(Context context, ConnectionInfo cInfo, boolean saveEdits) {
        synchronized (lockObj){
            String key = GetGlobeKey();
            // 不存在事务
            if (!transactionCache.containsKey(key)){
                return;
            }

            synchronized (lockObj) {
                int num = transactionRegs.get(key);
                num--;
                transactionRegs.put(key, num);
                if (num <= 0) {
                    HashMap<String, SQLiteDatabase> dbInfoList = transactionCache.get(key);
                    if (dbInfoList != null) {
                        if (hasInvokeRollback.get(key)){
                            saveEdits = false;
                        }
                        Set<String> keys = dbInfoList.keySet();
                        SQLiteDatabasePool pool = SQLiteDatabasePool.getInstance(context, cInfo, true);
                        for (String item : keys) {
                            SQLiteDatabase dataBase = dbInfoList.get(item);
                            if (saveEdits) {
                                dataBase.setTransactionSuccessful();
                                dataBase.endTransaction();
                            } else {
                                dataBase.endTransaction();
                            }
                            pool.releaseSQLiteDatabase(dataBase);
                        }
                    }

                    transactionCache.remove(key);
                    transactionRegs.remove(key);
                    hasInvokeRollback.remove(key);
                } else {
                    if (!saveEdits){
                        hasInvokeRollback.put(key, true);
                    }
                }
            }
        }
    }

    /**
     * 是否还存在下一个事务块
     * @return
     */
    public static boolean HasNextTransactions() {
        synchronized (lockObj) {
            String key = GetGlobeKey();
            if (!transactionRegs.containsKey(key)){
                return false;
            } else {
                if (transactionRegs.get(key) <= 0){
                    return false;
                } else {
                    return true;
                }
            }
        }
    }
}